home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 25 / AMIGAplus Sonderheft 25 (2000)(Falke)(DE)(Track 1 of 4)[!].iso / Tools / Text-Viewer / MSWordView / mswordview_src / roman.c < prev    next >
C/C++ Source or Header  |  2000-05-08  |  10KB  |  368 lines

  1. /* roman.c by Adam Rogoyski (apoc@laker.net) Temperanc on EFNet irc
  2.  * Copyright (C) 1998 Adam Rogoyski
  3.  * Converts Decimal numbers to Roman Numerals and Roman Numberals to
  4.  * Decimals on the command line or in Interactive mode.
  5.  * Uses an expanded Roman Numeral set to handle numbers up to 999999999
  6.  * compile: gcc -o roman roman.c -O2
  7.  * --- GNU General Public License Disclamer ---
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  */
  17.  
  18. #include <ctype.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22.  
  23. extern FILE *erroroutput;
  24.  
  25. #define I 1
  26. #define V 5
  27. #define X 10
  28. #define L 50
  29. #define C 100
  30. #define D 500
  31. #define M 1000
  32. #define P 5000
  33. #define Q 10000
  34. #define R 50000
  35. #define S 100000
  36. #define T 500000
  37. #define U 1000000
  38. #define B 5000000
  39. #define W 10000000
  40. #define N 50000000
  41. #define Y 100000000
  42. #define Z 500000000
  43.  
  44. #define LARGEST 999999999
  45.  
  46.  
  47. #include "roman.h"
  48.  
  49. #if 0
  50. int
  51. main (int argc, char **argv)
  52. {
  53.    char roman[81];
  54.    int i = 0;
  55.    long decimal = 0;
  56.    if (argc < 2)
  57.    {
  58.       char *buf = malloc (81);
  59.       if (!buf)
  60.       {
  61.          fprintf (erroroutput, "Not enough memory\n");
  62.          exit (EXIT_FAILURE);
  63.       }
  64.       printf ("Decimal <=> Roman Numberal converter by Adam Rogoyski\n");
  65.       printf ("Enter Decimals or Romans to convert, quit to stop\n");
  66.       printf ("Range: 1-999999999, I-ZYZWYUWSUQSMQCMXCIX\n\n==> ");
  67.       fflush (stdout);
  68.       memset (buf, 0, 81);
  69.       while (strncasecmp(fgets(buf, 81, stdin) ? buf : "", "quit", 4))
  70.       {
  71.          if (!buf[0])
  72.             exit (EXIT_SUCCESS);
  73.          i = 0;
  74.          while (isspace(buf[i]))
  75.             i++;
  76.          if (isdigit(buf[i]))
  77.             puts (decimalToRoman(atoi(buf), roman));
  78.          else
  79.          {
  80.             if (isupper(buf[i]))
  81.             {
  82.                chomp (buf);
  83.                decimal = romanToDecimal(buf);
  84.                if (decimal)
  85.                   printf ("%ld\n", decimal);
  86.             }
  87.          }
  88.          printf ("==> ");
  89.          fflush (stdout);
  90.          memset (buf, 0, 80);
  91.       }
  92.       free (buf);
  93.    }
  94.    else
  95.    {
  96.       while (argc-- >= 2)
  97.       {
  98.          memset (roman, 0, 81);
  99.          if (isdigit(**(argv + 1)))
  100.          {
  101.             decimal = atoi (*(argv + 1));
  102.             puts (decimalToRoman(decimal, roman));
  103.          }
  104.          else
  105.          {
  106.             decimal = romanToDecimal(*(argv + 1));
  107.             if (decimal)
  108.                printf ("%ld\n", decimal);
  109.          }
  110.          argv++;
  111.       }
  112.    }
  113.    return EXIT_SUCCESS;
  114. }
  115. #endif 
  116.  
  117. long
  118. formString (char **r, long v, char a, char b)
  119. {
  120.    *(*r)++ = a;
  121.    if (b)
  122.       *(*r)++ = b;
  123.    return v;
  124. }
  125.  
  126. char * decimalToRoman (long decimal, char *roman)
  127. {
  128.    char *r = roman;
  129.    memset (roman, 0, 81);
  130.    r = roman;
  131.    if (decimal > LARGEST || decimal < 1)
  132.    {
  133.       *r = '\0';
  134.       fprintf(erroroutput,"roman broke\n");
  135.       return roman;
  136.    }
  137.    if (decimal >= Z)
  138.       decimal -= formString (&r, Z, 'Z', '\0');
  139.    if (decimal >= Z - Y)
  140.       decimal -= formString (&r, Z - Y, 'Y', 'Z');
  141.    while (decimal >= Y)
  142.       decimal -= formString (&r, Y, 'Y', '\0');
  143.    if (decimal >= Y - W)
  144.       decimal -= formString (&r, Y - W, 'W', 'Y');
  145.    if (decimal >= N)
  146.       decimal -= formString (&r, N, 'N', '\0');
  147.    if (decimal >= N - W)
  148.       decimal -= formString (&r, N - W, 'W', 'N');
  149.    while (decimal >= W)
  150.       decimal -= formString (&r, W, 'W', '\0');
  151.    if (decimal >= W - U)
  152.       decimal -= formString (&r, W - U, 'U', 'W');
  153.    if (decimal >= B)
  154.       decimal -= formString (&r, B, 'B', '\0');
  155.    if (decimal >= B - U)
  156.       decimal -= formString (&r, B - U, 'U', 'B');
  157.    while (decimal >= U)
  158.       decimal -= formString (&r, U, 'U', '\0');
  159.    if (decimal >= U - S)
  160.       decimal -= formString (&r, U - S, 'S', 'U');
  161.    if (decimal >= T)
  162.       decimal -= formString (&r, T, 'T', '\0');
  163.    if (decimal >= T - S)
  164.       decimal -= formString (&r, T - S, 'S', 'T');
  165.    while (decimal >= S)
  166.       decimal -= formString (&r, S, 'S', '\0');
  167.    if (decimal >= S - Q)
  168.       decimal -= formString (&r, S - Q, 'Q', 'S');
  169.    if (decimal >= R)
  170.       decimal -= formString (&r, R, 'R', '\0');
  171.    if (decimal >= R - Q)
  172.       decimal -= formString (&r, R - Q, 'Q', 'R');
  173.    while (decimal >= Q)
  174.       decimal -= formString (&r, Q, 'Q', '\0');
  175.    if (decimal >= Q - M)
  176.       decimal -= formString (&r, Q - M, 'M', 'Q');
  177.    if (decimal >= P)
  178.       decimal -= formString (&r, P, 'P', '\0');
  179.    if (decimal >= P - M)
  180.       decimal -= formString (&r, P - M, 'M', 'P');
  181.    while (decimal >= M)
  182.       decimal -= formString (&r, M, 'M', '\0');
  183.    if (decimal >= M - C)
  184.       decimal -= formString (&r, M - C, 'C', 'M');
  185.    if (decimal >= D)
  186.       decimal -= formString (&r, D, 'D', '\0');
  187.    if (decimal >= D - C)
  188.       decimal -= formString (&r, D - C, 'C', 'D');
  189.    while (decimal >= C)
  190.       decimal -= formString (&r, C, 'C', '\0');
  191.    if (decimal >= C - X)
  192.       decimal -= formString (&r, C - X, 'X', 'C');
  193.    if (decimal >= L)
  194.       decimal -= formString (&r, L, 'L', '\0');
  195.    if (decimal >= L - X)
  196.       decimal -= formString (&r, L - X, 'X', 'L');
  197.    while (decimal >= X)
  198.       decimal -= formString (&r, X, 'X', '\0');
  199.    switch ((int) decimal)
  200.    {
  201.       case 9:
  202.          *r++ = 'I';
  203.          *r++ = 'X';
  204.          break;
  205.       case 8:
  206.          *r++ = 'V';
  207.          *r++ = 'I';
  208.          *r++ = 'I';
  209.          *r++ = 'I';
  210.          break;
  211.       case 7:
  212.          *r++ = 'V';
  213.          *r++ = 'I';
  214.          *r++ = 'I';
  215.          break;
  216.       case 6:
  217.          *r++ = 'V';
  218.          *r++ = 'I';
  219.          break;
  220.       case 4:
  221.          *r++ = 'I';
  222.       case 5:
  223.          *r++ = 'V';
  224.          break;
  225.       case 3:
  226.          *r++ = 'I';
  227.       case 2:
  228.          *r++ = 'I';
  229.       case 1:
  230.          *r++ = 'I';
  231.          break;
  232.    }
  233.    return roman;
  234. }
  235.  
  236.  
  237. long
  238. romanToDecimal (char *roman)
  239. {
  240.    long decimal = 0;
  241.    for (; *roman; roman++)
  242.    {
  243.       /* Check for four of a letter in a fow */
  244.       if ((*(roman + 1) && *(roman + 2) && *(roman + 3))
  245.          && (*roman == *(roman + 1))
  246.          && (*roman == *(roman + 2))
  247.          && (*roman == *(roman + 3)))
  248.          return 0;
  249.       /* Check for two five type numbers */
  250.       if (  ((*roman == 'V') && (*(roman + 1) == 'V'))
  251.          || ((*roman == 'L') && (*(roman + 1) == 'L'))
  252.          || ((*roman == 'D') && (*(roman + 1) == 'D'))
  253.          || ((*roman == 'P') && (*(roman + 1) == 'P'))
  254.          || ((*roman == 'R') && (*(roman + 1) == 'R'))
  255.          || ((*roman == 'T') && (*(roman + 1) == 'T'))
  256.          || ((*roman == 'B') && (*(roman + 1) == 'B'))
  257.          || ((*roman == 'N') && (*(roman + 1) == 'N'))
  258.          || ((*roman == 'Z') && (*(roman + 1) == 'Z')))
  259.          return 0;
  260.       /* Check for two lower characters before a larger one */
  261.       if ((value(*roman) == value(*(roman + 1))) && (*(roman + 2))
  262.          && (value(*(roman + 1)) < value(*(roman + 2))))
  263.          return 0;
  264.       /* Check for the same character on either side of a larger one */
  265.       if ((*(roman + 1) && *(roman + 2)) 
  266.          && (value(*roman) == value(*(roman + 2)))
  267.          && (value(*roman) < value(*(roman + 1))))
  268.          return 0;
  269.       /* Check for illegal nine type numbers */
  270.       if (!strncmp(roman, "LXL", 3) || !strncmp(roman, "DCD", 3)
  271.        || !strncmp(roman, "PMP", 3) || !strncmp(roman, "RQR", 3)
  272.        || !strncmp(roman, "TST", 3) || !strncmp(roman, "BUB", 3)
  273.        || !strncmp(roman, "NWN", 3) || !strncmp(roman, "VIV", 3))
  274.          return 0;
  275.       if (value(*roman) < value(*(roman + 1)))
  276.       {
  277.          /* check that subtracted value is at least 10% larger, 
  278.             i.e. 1990 is not MXM, but MCMXC */
  279.          if ((10 * value(*roman)) < value(*(roman + 1)))
  280.             return 0;
  281.          /* check for double subtraction, i.e. IVX */
  282.          if (value(*(roman + 1)) <= value(*(roman + 2